// Tencent is pleased to support the open source community by making
// 蓝鲸智云 - 监控平台/日志平台 (BlueKing - Monitor/Log) available.
// Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. All rights reserved.
// Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://opensource.org/licenses/MIT
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//

package tracesderiver

import (
	"fmt"
	"sort"
	"strings"

	"github.com/TencentBlueKing/bkmonitor-kits/logger"

	"github.com/TencentBlueKing/bk-collector/define"
	"github.com/TencentBlueKing/bk-collector/internal/utils"
)

type Config struct {
	Operations []OperationConfig `config:"operations" mapstructure:"operations"`
}

type OperationConfig struct {
	Type       string       `config:"type" mapstructure:"type"`
	MetricName string       `config:"metric_name" mapstructure:"metric_name"`
	Rules      []RuleConfig `config:"rules" mapstructure:"rules"`
}

type RuleConfig struct {
	Kind         string   `config:"kind" mapstructure:"kind"`
	PredicateKey string   `config:"predicate_key" mapstructure:"predicate_key"`
	Dimensions   []string `config:"dimensions" mapstructure:"dimensions"`
}

type TypeWithName struct {
	Type       string
	MetricName string
}

type ConfigHandler struct {
	types         []TypeWithName
	kinds         map[string][]RuleConfig // key:[type+kind]
	predicateKeys *utils.MapUniqueStrings // key:[type+kind]
	resourceKeys  *utils.MapUniqueStrings // key:[type]
	attributeKeys *utils.MapUniqueStrings // key:[type+kind+predicateKey]
	methodKeys    *utils.MapUniqueStrings // key:[type+kind+predicateKey]
}

// NewConfigHandler 创建并返回 ConfigHandler 实例 用于管理配置和提取内容
// 使用一些列 map 来存储配置字段是为了不在运行时产生高频的解析开销 降低内存消耗
// 另外 Map(~O(1)) 的性能要比 Range(~O(N)) 优异
func NewConfigHandler(config Config) *ConfigHandler {
	kinds := make(map[string][]RuleConfig)
	predicateKeys := utils.NewMapUniqueStrings()
	resourceKeys := utils.NewMapUniqueStrings()
	attributeKeys := utils.NewMapUniqueStrings()
	methodKeys := utils.NewMapUniqueStrings()

	var types []TypeWithName
	for i := 0; i < len(config.Operations); i++ {
		conf := config.Operations[i]
		if extractor := ExtractorMap[conf.Type]; extractor == nil {
			logger.Errorf("invalid extractor type: %s", conf.Type)
			continue
		}

		types = append(types, TypeWithName{
			Type:       conf.Type,
			MetricName: conf.MetricName,
		})

		for j := 0; j < len(conf.Rules); j++ {
			kind := conf.Rules[j]
			key := fmt.Sprintf("%s/%s", conf.Type, kind.Kind)
			kinds[key] = append(kinds[key], kind)
			predicateKeys.Set(key, kind.PredicateKey)

			for k := 0; k < len(kind.Dimensions); k++ {
				dim := kind.Dimensions[k]
				id := fmt.Sprintf("%s/%s/%s", conf.Type, kind.Kind, kind.PredicateKey)
				switch {
				case strings.HasPrefix(dim, define.ResourceKeyPrefix):
					resourceKeys.Set(conf.Type, dim[len(define.ResourceKeyPrefix):])
				case strings.HasPrefix(dim, define.AttributeKeyPrefix):
					attributeKeys.Set(id, dim[len(define.AttributeKeyPrefix):])
				default:
					methodKeys.Set(id, dim)
				}
			}
		}
	}

	return &ConfigHandler{
		types:         types,
		predicateKeys: predicateKeys,
		resourceKeys:  resourceKeys,
		attributeKeys: attributeKeys,
		methodKeys:    methodKeys,
		kinds:         kinds,
	}
}

func (ch *ConfigHandler) GetTypes() []TypeWithName {
	return ch.types
}

func (ch *ConfigHandler) GetResourceKeys(t string) []string {
	return ch.resourceKeys.Get(t)
}

func (ch *ConfigHandler) GetPredicateKeys(t, kind string) []string {
	keys := ch.predicateKeys.Get(fmt.Sprintf("%s/%s", t, kind))
	sort.Slice(keys, func(i, j int) bool {
		return keys[i] >= keys[j]
	})

	// 如果没查到 那就使用兜底配置
	if len(keys) == 0 {
		keys = ch.predicateKeys.Get(fmt.Sprintf("%s/", t))
		sort.Slice(keys, func(i, j int) bool {
			return keys[i] >= keys[j]
		})
	}
	return keys
}

func (ch *ConfigHandler) GetAttributes(t, kind, predicateKey string) []string {
	keys := ch.attributeKeys.Get(fmt.Sprintf("%s/%s/%s", t, kind, predicateKey))
	// 使用兜底配置
	if len(keys) == 0 && predicateKey == "" {
		return ch.attributeKeys.Get(fmt.Sprintf("%s//%s", t, predicateKey))
	}
	return keys
}

func (ch *ConfigHandler) GetMethods(t, kind, predicateKey string) []string {
	keys := ch.methodKeys.Get(fmt.Sprintf("%s/%s/%s", t, kind, predicateKey))
	// 使用兜底配置
	if len(keys) == 0 && predicateKey == "" {
		return ch.methodKeys.Get(fmt.Sprintf("%s//%s", t, predicateKey))
	}
	return keys
}
